﻿// 2025/10/14: 首个版本

using System;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Avalonia.Input;
using ASEva;
using ASEva.UIAvalonia;
using ASEva.Utility;
using Avalonia.Controls;

namespace CommonSource
{
    partial class DataEncryptionConfigDialog : DialogPanel
    {
        public DataEncryptionConfigDialog() // For designer
        {
            InitializeComponent();
            language = new LanguageSwitch(Resources, AgencyLocal.GetAppLanguage());
        }

        public DataEncryptionConfigDialog(WorkflowEncryptionCallback callback, String iconResourceName = null)
        {
            Assert.HostSide();

            InitializeComponent();
            SetFixMode(450, 310, true);
            language = new LanguageSwitch(Resources, AgencyLocal.GetAppLanguage());
            Icon = ResourceLoader.Load(iconResourceName)?.ToAvaloniaWindowIcon();
            Title = language["title"];

            var defaultPassword = callback.UnlockDataKey(null);
            var model = new DataEncryptionConfigDialogViewModel(language, defaultPassword, callback);
            if (defaultPassword)
            {
                model.CanInputUpdate = true;
                delayFocus(textNew);
            }
            else
            {
                model.CanInputUnlock = true;
                delayFocus(textOld);
            }
            DataContext = model;

            model.PasswordUnlocked += (o, e) => textNew.Focus();
            model.PasswordUpdated += (o, e) => Close();

            textOld.KeyUp += (o, e) =>
            {
                if (e.Key == Key.Enter)
                {
                    if (model.CanUnlock) model.Unlock();
                }
            };

            textNew.KeyDown += (o, e) =>
            {
                if (e.Key == Key.Enter)
                {
                    textConfirm.Focus();
                    if (model.CanUpdate) model.Update();
                }
            };

            textConfirm.KeyDown += (o, e) =>
            {
                if (e.Key == Key.Enter)
                {
                    if (model.CanUpdate) model.Update();
                }
            };
        }

        private async void delayFocus(TextBox textBox)
        {
            await Task.Delay(300);
            textBox.Focus();
        }

        private LanguageSwitch language;
    }

    partial class DataEncryptionConfigDialogViewModel(LanguageSwitch language, bool defaultPassword, WorkflowEncryptionCallback callback) : ObservableObject
    {
        // Options ///////////////////////////////////////////////////////////////////////////////////////////////////////////

        [ObservableProperty]
        private bool isRecordEncryptionEnabled = AgencyAsync.GetGlobalParameter("System.RecordEncryption", "no").Result == "yes";

        partial void OnIsRecordEncryptionEnabledChanged(bool value)
        {
            AgencyAsync.SetGlobalParameter("System.RecordEncryption", value ? "yes" : "no");
        }

        // Unlock ///////////////////////////////////////////////////////////////////////////////////////////////////////////

        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(CanUnlock))]
        private string oldPassword = "";

        [ObservableProperty]
        private bool canInputUnlock = false;

        public bool CanUnlock => !CanInputUpdate && OldPassword.Length > 0;

        public String UnlockText => CanInputUpdate ? language["unlocked"] : language["unlock"];

        [RelayCommand]
        public void Unlock()
        {
            if (callback.UnlockDataKey(OldPassword))
            {
                CanInputUnlock = false;
                CanInputUpdate = true;
                PasswordUnlocked?.Invoke(this, EventArgs.Empty);
            }
            else
            {
                App.ShowMessageBox(language["wrong-password"]);
            }
        }

        // Update ///////////////////////////////////////////////////////////////////////////////////////////////////////////

        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(CanUpdate))]
        private string newPassword = "";

        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(CanUpdate))]
        private string confirmPassword = "";

        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(CanUnlock))]
        [NotifyPropertyChangedFor(nameof(UnlockText))]
        [NotifyPropertyChangedFor(nameof(CanUpdate))]
        private bool canInputUpdate = false;

        public bool CanUpdate
        {
            get
            {
                if (!CanInputUpdate) return false;
                var confirmed = NewPassword == ConfirmPassword;
                if (!defaultPassword) return confirmed;
                else return confirmed && NewPassword.Length > 0;
            }
        }

        [RelayCommand]
        public void Update()
        {
            callback.UpdateDataKey(NewPassword.Length == 0 ? null : NewPassword);
            App.ShowMessageBox(language["password-updated"]);
            PasswordUpdated?.Invoke(this, EventArgs.Empty);
        }

        // Events ///////////////////////////////////////////////////////////////////////////////////////////////////////////

        public event EventHandler<EventArgs> PasswordUnlocked;

        public event EventHandler<EventArgs> PasswordUpdated;
    }
}